//
// Created by LONG on 2020/10/18.
//

#include "nbFsm.h"
#include "../../../../../ccore/sctp/include/sctpApi.h"
#include "../../../../../ccore/misc/include/misc.h"

void RAN_L3_NB_SMH_Default(uint32_t state, S_FsmEventContext *evtCtxt, S_FsmHandleResult *result)
{
    result->procRslt = O5G_RC_OK;
}

void RAN_L3_NB_SMH_ProcSctpSetupTrigger(uint32_t state, S_FsmEventContext *evtCtxt, S_FsmHandleResult *result)
{
    int32_t rc;
    S_RanL3NbInst *pNbInst;

    pNbInst = (S_RanL3NbInst *)evtCtxt->context;
    rc = SCTPC_Connect(pNbInst->sctpFd, pNbInst->amfIp.addr4, NGAP_SCTP_PORT);
    if (O5G_RC_OK != rc)
    {
        CSP_LOG_INF(RAN_MD_L3_NBM, "SCTPC_Connect() failure.\n");
        result->procRslt = O5G_RC_ER;
        return;
    }
    CSP_LOG_INF(RAN_MD_L3_NBM, "sctp connect success. amf ip : %s\n", (char *)pNbInst->amfIp.addr4);

    /* TODO:send ngap setup req */

    result->newEventInd = 1;
    result->newEvent = RAN_L3_NB_SM_EVENT_RECV_NGAP_SETUP_RSP;
    result->newContext = evtCtxt->context;
    result->procRslt = O5G_RC_OK;
}

void RAN_L3_NB_SMH_ProcNgapSetupRsp(uint32_t state, S_FsmEventContext *evtCtxt, S_FsmHandleResult *result)
{
    RAN_ADD_DBG_CODE(RAN_DC_L3_NGAP_SETUP_SUCC);
    result->procRslt = O5G_RC_OK;
}

FSM_DEF_BEG(RAN_L3_NB_FSM, RAN_L3_NB_SM_STATE_INIT)

    FSM_STATE_DEF_BEG(RAN_L3_NB_SM_STATE_INIT)
        FSM_EVENT_HANDLE_DEF(RAN_L3_NB_SM_EVENT_SCTP_SETUP_TRIGGER, RAN_L3_NB_SMH_ProcSctpSetupTrigger)
            FSM_STATE_TRANS_DEF(O5G_RC_OK, RAN_L3_NB_SM_STATE_WAIT_NGAP_SETUP_RSP)
            FSM_STATE_TRANS_DEF(O5G_RC_ER, RAN_L3_NB_SM_STATE_INIT)
        FSM_DEFAULT_EVENT_HANDLE_DEF(RAN_L3_NB_SMH_Default)
            FSM_STATE_TRANS_DEF(O5G_RC_OK, RAN_L3_NB_SM_STATE_INIT)
            FSM_STATE_TRANS_DEF(O5G_RC_ER, RAN_L3_NB_SM_STATE_INIT)
    FSM_STATE_DEF_END(RAN_L3_NB_SM_STATE_INIT)

    FSM_STATE_DEF_BEG(RAN_L3_NB_SM_STATE_WAIT_NGAP_SETUP_RSP)
        FSM_EVENT_HANDLE_DEF(RAN_L3_NB_SM_EVENT_RECV_NGAP_SETUP_RSP, RAN_L3_NB_SMH_ProcNgapSetupRsp)
            FSM_STATE_TRANS_DEF(O5G_RC_OK, RAN_L3_NB_SM_STATE_NGAP_SETUP_SUCC)
            FSM_STATE_TRANS_DEF(O5G_RC_ER, RAN_L3_NB_SM_STATE_INIT)
        FSM_DEFAULT_EVENT_HANDLE_DEF(RAN_L3_NB_SMH_Default)
            FSM_STATE_TRANS_DEF(O5G_RC_OK, RAN_L3_NB_SM_STATE_INIT)
            FSM_STATE_TRANS_DEF(O5G_RC_ER, RAN_L3_NB_SM_STATE_INIT)
    FSM_STATE_DEF_END(RAN_L3_NB_SM_STATE_WAIT_NGAP_SETUP_RSP)

FSM_DEF_END(RAN_L3_NB_FSM)

int32_t RAN_L3_NB_SM_Init(void)
{
    uint32_t loop;
    S_RanL3NbInst *pNbInst;
    char fsmInstId[64];

    gpRanL3Context->nbFsm = FSM_INIT(RAN_L3_NB_FSM);
    IF_RETURN(==, NULL, gpRanL3Context->nbFsm, O5G_RC_ER, "RAN_L3_NB_SM_Init() FSM_INIT(RAN_L3_NB_FSM) error!\n");

    FSM_SetLogCallback(gpRanL3Context->nbFsm, O5G_FSM_Print);

    for (loop = 0; loop < RAN_NODEB_NUM_MAX; loop++)
    {
        pNbInst = &gpRanL3Context->nbInst[loop];
        snprintf(fsmInstId, sizeof(fsmInstId), "nb:%u", pNbInst->nbIdx);
        pNbInst->nbSmInst = FSM_INST_Init(gpRanL3Context->nbFsm, fsmInstId);
        IF_RETURN(==, NULL, pNbInst->nbSmInst, O5G_RC_ER, "RAN_L3_NB_SM_Init() FSM_INST_Init() error!\n");
    }

    gpRanL3Context->nbFsmEvtQue = FixRB_Create(NULL, 16, sizeof(S_FsmEventContext), FIX_RB_TYPE_NONE);
    IF_RETURN(==, NULL, gpRanL3Context->nbFsmEvtQue, O5G_RC_ER, "RAN_L3_NB_SM_Init() FixRB_Create() error!\n");

    return O5G_RC_OK;
}

int32_t RAN_L3_NB_SM_Final(void)
{
    uint32_t loop;
    S_RanL3NbInst *pNbInst;

    for (loop = 0; loop < RAN_NODEB_NUM_MAX; loop++)
    {
        pNbInst = &gpRanL3Context->nbInst[loop];
        FSM_INST_Final(pNbInst->nbSmInst);
    }
    FSM_Final(gpRanL3Context->nbFsm);
    FixRB_Destroy(gpRanL3Context->nbFsmEvtQue);

    return O5G_RC_OK;
}

void RAN_L3_NB_SM_ProcFsmEvent()
{
    int32_t rc;
    S_RanL3NbInst *pNbInst;
    uint32_t size;
    S_FsmEventContext evtCtxt;

    while (1)
    {
        size = sizeof(evtCtxt);
        rc = FixRB_Get(gpRanL3Context->nbFsmEvtQue, &evtCtxt, &size);
        IF_BREAK(!=, CSP_RC_OK, rc, NO_LOG_MESSAGE);

        pNbInst = (S_RanL3NbInst *)evtCtxt.context;
        FSM_INST_HandleEvent(pNbInst->nbSmInst, &evtCtxt);
    }
}

void RAN_L3_NB_SM_IndProcess(S_OsSelectInd *pIndMsg)
{
    switch (pIndMsg->ind)
    {
    case RAN_L3_INTRA_IND_MSG_NB_FSM_EVT:
        RAN_L3_NB_SM_ProcFsmEvent();
        break;
    default:
        break;
    }
}

void RAN_L3_NB_SM_MsgProcess(void)
{

}

void RAN_L3_NB_SM_PrdProcess(void)
{
    uint32_t loop;
    uint32_t needSendInd;
    S_RanL3NbInst *pNbInst;
    S_FsmEventContext evtCtxt;
    S_OsSelectInd indMsg;

    needSendInd = FALSE;

    if (0 != gpRanL3Context->tick10ms % 10)
    {
        return;
    }

    for (loop = 0; loop < gpRanL3Context->nbNum; loop++)
    {
        pNbInst = &gpRanL3Context->nbInst[loop];
        IF_CONTINUE(==, FALSE, pNbInst->inUse, NO_LOG_MESSAGE);

        if (RAN_L3_NB_SM_STATE_INIT != FSM_INST_GetState(pNbInst->nbSmInst))
        {
            continue;
        }

        evtCtxt.event = RAN_L3_NB_SM_EVENT_SCTP_SETUP_TRIGGER;
        evtCtxt.context = pNbInst;
        FixRB_Put(gpRanL3Context->nbFsmEvtQue, &evtCtxt, sizeof(evtCtxt));

        needSendInd = TRUE;
    }

    if (needSendInd)
    {
        indMsg.ind = RAN_L3_INTRA_IND_MSG_NB_FSM_EVT;
        OS_SelectSend(&gpRanL3Context->selector, &indMsg);
    }
}